compatibility_tags.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. """Generate and work with PEP 425 Compatibility Tags.
  2. """
  3. from __future__ import absolute_import
  4. import re
  5. from pip._vendor.packaging.tags import (
  6. Tag,
  7. compatible_tags,
  8. cpython_tags,
  9. generic_tags,
  10. interpreter_name,
  11. interpreter_version,
  12. mac_platforms,
  13. )
  14. from pip._internal.utils.typing import MYPY_CHECK_RUNNING
  15. if MYPY_CHECK_RUNNING:
  16. from typing import List, Optional, Tuple
  17. from pip._vendor.packaging.tags import PythonVersion
  18. _osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)')
  19. def version_info_to_nodot(version_info):
  20. # type: (Tuple[int, ...]) -> str
  21. # Only use up to the first two numbers.
  22. return ''.join(map(str, version_info[:2]))
  23. def _mac_platforms(arch):
  24. # type: (str) -> List[str]
  25. match = _osx_arch_pat.match(arch)
  26. if match:
  27. name, major, minor, actual_arch = match.groups()
  28. mac_version = (int(major), int(minor))
  29. arches = [
  30. # Since we have always only checked that the platform starts
  31. # with "macosx", for backwards-compatibility we extract the
  32. # actual prefix provided by the user in case they provided
  33. # something like "macosxcustom_". It may be good to remove
  34. # this as undocumented or deprecate it in the future.
  35. '{}_{}'.format(name, arch[len('macosx_'):])
  36. for arch in mac_platforms(mac_version, actual_arch)
  37. ]
  38. else:
  39. # arch pattern didn't match (?!)
  40. arches = [arch]
  41. return arches
  42. def _custom_manylinux_platforms(arch):
  43. # type: (str) -> List[str]
  44. arches = [arch]
  45. arch_prefix, arch_sep, arch_suffix = arch.partition('_')
  46. if arch_prefix == 'manylinux2014':
  47. # manylinux1/manylinux2010 wheels run on most manylinux2014 systems
  48. # with the exception of wheels depending on ncurses. PEP 599 states
  49. # manylinux1/manylinux2010 wheels should be considered
  50. # manylinux2014 wheels:
  51. # https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels
  52. if arch_suffix in {'i686', 'x86_64'}:
  53. arches.append('manylinux2010' + arch_sep + arch_suffix)
  54. arches.append('manylinux1' + arch_sep + arch_suffix)
  55. elif arch_prefix == 'manylinux2010':
  56. # manylinux1 wheels run on most manylinux2010 systems with the
  57. # exception of wheels depending on ncurses. PEP 571 states
  58. # manylinux1 wheels should be considered manylinux2010 wheels:
  59. # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels
  60. arches.append('manylinux1' + arch_sep + arch_suffix)
  61. return arches
  62. def _get_custom_platforms(arch):
  63. # type: (str) -> List[str]
  64. arch_prefix, arch_sep, arch_suffix = arch.partition('_')
  65. if arch.startswith('macosx'):
  66. arches = _mac_platforms(arch)
  67. elif arch_prefix in ['manylinux2014', 'manylinux2010']:
  68. arches = _custom_manylinux_platforms(arch)
  69. else:
  70. arches = [arch]
  71. return arches
  72. def _get_python_version(version):
  73. # type: (str) -> PythonVersion
  74. if len(version) > 1:
  75. return int(version[0]), int(version[1:])
  76. else:
  77. return (int(version[0]),)
  78. def _get_custom_interpreter(implementation=None, version=None):
  79. # type: (Optional[str], Optional[str]) -> str
  80. if implementation is None:
  81. implementation = interpreter_name()
  82. if version is None:
  83. version = interpreter_version()
  84. return "{}{}".format(implementation, version)
  85. def get_supported(
  86. version=None, # type: Optional[str]
  87. platform=None, # type: Optional[str]
  88. impl=None, # type: Optional[str]
  89. abi=None # type: Optional[str]
  90. ):
  91. # type: (...) -> List[Tag]
  92. """Return a list of supported tags for each version specified in
  93. `versions`.
  94. :param version: a string version, of the form "33" or "32",
  95. or None. The version will be assumed to support our ABI.
  96. :param platform: specify the exact platform you want valid
  97. tags for, or None. If None, use the local system platform.
  98. :param impl: specify the exact implementation you want valid
  99. tags for, or None. If None, use the local interpreter impl.
  100. :param abi: specify the exact abi you want valid
  101. tags for, or None. If None, use the local interpreter abi.
  102. """
  103. supported = [] # type: List[Tag]
  104. python_version = None # type: Optional[PythonVersion]
  105. if version is not None:
  106. python_version = _get_python_version(version)
  107. interpreter = _get_custom_interpreter(impl, version)
  108. abis = None # type: Optional[List[str]]
  109. if abi is not None:
  110. abis = [abi]
  111. platforms = None # type: Optional[List[str]]
  112. if platform is not None:
  113. platforms = _get_custom_platforms(platform)
  114. is_cpython = (impl or interpreter_name()) == "cp"
  115. if is_cpython:
  116. supported.extend(
  117. cpython_tags(
  118. python_version=python_version,
  119. abis=abis,
  120. platforms=platforms,
  121. )
  122. )
  123. else:
  124. supported.extend(
  125. generic_tags(
  126. interpreter=interpreter,
  127. abis=abis,
  128. platforms=platforms,
  129. )
  130. )
  131. supported.extend(
  132. compatible_tags(
  133. python_version=python_version,
  134. interpreter=interpreter,
  135. platforms=platforms,
  136. )
  137. )
  138. return supported